/******************************************************************************
*	usbd/device.h
*	 by Alex Chadwick
*
*	A light weight implementation of the USB protocol stack fit for a simple
*	driver.
*
*	usbd/device.h contains a definition of a device structure used for
*	storing devices and the device tree.
******************************************************************************/
#ifndef _USBD_DEVICE_H
#define _USBD_DEVICE_H

#include <usbd/descriptors.h>
#include <types.h>

//------------------------------------------------------------------------------
// The maximum number of children a device may have.
//
// By implication, this is the maximum number of ports a hub supports.
// Theoretically, this is 255 (as 8 bits are used to transfer the port count in
//   a hub descriptor), but in practice, few hubs have more than 10,
// Increasing this value (without good cause) will waste memory
// Decreasing this value will save a little memory in the HubDevice structure,
//   but may removing support for an otherwise valid hub.
//
#define MaxChildrenPerDevice  (10)  // 1 <= N <= 255

//------------------------------------------------------------------------------
// The maximum number of interfaces a device configuration may have.
//
// Theoretically, this is 255 (as one byte is used to transfer the interface
//   count in a configuration descriptor), but in practice this is unlikely,
//   so we allow (an arbitrary choice of) 8.
// Increasing this value (without good casue) will waste (a lot) of memory in
//   every device structure.
// Decreasing this value reduces the overheads of the UsbDevice structure,
//   but may reject support for an otherwise supportable device.
//
#define MaxInterfacesPerDevice  (8)  // 1 <= N <= 255

//------------------------------------------------------------------------------
// The maximum number of endpoints a device could have (per interface).
//
// Theoretically, this is 16, as four bits are used to transfer the endpoint
//   number in certain device requests. This is also possible in practice, so we
//   allow that many.
// Decreasing this value considerably reduces the memory required for each
//   device structure, but may remove support for otherwise valid devices.
//
#define MaxEndpointsPerDevice  (16)  // 1 <= N <= 16

//------------------------------------------------------------------------------
// USB device: Status
// Defined in "USB Sepcification, Rev 2.0, 27/Apr/2000" section 9.1
//
typedef
	enum UsbDeviceStatus {
		Attached   = 0,
		Powered    = 1,
		Default    = 2,
		Addressed  = 3,
		Configured = 4,
	}
UsbDeviceStatus;

//------------------------------------------------------------------------------
// The status of the last transfer performed by the USB device
//
typedef
	enum UsbTransferError {
		NoError         = 0,
		Stall           = 1 <<  1,
		BufferError     = 1 <<  2,
		Babble          = 1 <<  3,
		NoAcknowledge   = 1 <<  4,
		CrcError        = 1 <<  5,
		BitError        = 1 <<  6,
		ConnectionError = 1 <<  7,
		AhbError        = 1 <<  8,
		NotYetError     = 1 <<  9,
		Processing      = 1 << 31,
	}
UsbTransferError;

//------------------------------------------------------------------------------
// USB driver: Data header of a device specific data field.
//
// DeviceDriver : A code which uniquely identifies the driver that set the driver data
//                I.e. The lowest driver in the stack above the USB driver
// DataSize     : The byte-size of the device specific data field.
//
typedef
	struct UsbDriverDataHeader {
		u32  DeviceDriver;
		u32  DataSize;
	}
UsbDriverDataHeader;

//------------------------------------------------------------------------------
// Details of a detected USB device
//
// This is not directly part of the USB standard, and is instead a mechanism
//   used to control the device tree.
//
typedef struct UsbDevice UsbDevice ; // forward definition for embedded function-pointers

typedef
	struct UsbDevice {
		         u32              Number;

		         UsbSpeed         Speed;
		         UsbDeviceStatus  Status;
		volatile u8               ConfigurationIndex;
		         u8               PortNumber;
		volatile UsbTransferError Error  ALIGN4;

		// --- Generic Handlers for all devices ---
		// Detach device - stop issuing requests to the device.
		void (*DeviceDetached         )(UsbDevice* device)  ALIGN4;
		// Deallocate device - free all memory used by the device.
		void (*DeviceDeallocate       )(UsbDevice* device);
		// --- Generic Handlers for hubs ---
		// Check the device tree for changes.
		void (*DeviceCheckForChange   )(UsbDevice* device);
		// Remove a child device.
		void (*DeviceChildDetached    )(UsbDevice* device, UsbDevice* child);
		// Reset a child device.
		Result (*DeviceChildReset     )(UsbDevice* device, UsbDevice* child);
		// ???
		Result (*DeviceCheckConnection)(UsbDevice* device, UsbDevice* child);

		volatile UsbDeviceDescriptor        Descriptor  ALIGN4;
		volatile UsbConfigurationDescriptor Configuration  ALIGN4;
		volatile UsbInterfaceDescriptor     Interfaces[MaxInterfacesPerDevice]  ALIGN4;
		volatile UsbEndpointDescriptor      Endpoints[MaxInterfacesPerDevice][MaxEndpointsPerDevice]  ALIGN4;
		         UsbDevice                  *Parent  ALIGN4;
		volatile void                       *FullConfiguration;
		volatile UsbDriverDataHeader        *DriverData;
		volatile u32                        LastTransfer;
	}
UsbDevice;

//------------------------------------------------------------------------------
// An array of methods (function-pointers) to attach an interface of a given class.
//
// The class of the interface is the index into the method array.
// The array is populated by ConfigurationLoad()
//
#define InterfaceClassAttachCount  (16)  // Maximum number of methods available

extern  Result (*InterfaceClassAttach[InterfaceClassAttachCount])(UsbDevice* device, u32 interfaceNumber);

#endif // _USBD_DEVICE_H
